# -*- coding: iso-8859-15 -*-
# 
# LICENSE:
# 
# Copyright 2008 Håkan Lindqvist. All rights reserved.
# 
# Redistribution and use in source and binary forms, 
# with or without modification, are permitted provided 
# that the following conditions are met:
# 
#    1. Redistributions of source code must retain the 
#       above copyright notice, this list of conditions 
#       and the following disclaimer.
#    2. Redistributions in binary form must reproduce the 
#       above copyright notice, this list of conditions 
#       and the following disclaimer in the documentation 
#       and/or other materials provided with the distribution.
# 
# THIS SOFTWARE IS PROVIDED BY HÅKAN LINDQVIST ``AS IS'' 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL HÅKAN LINDQVIST 
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
# DAMAGE.
# 

import os
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class RequestHandler(BaseHTTPRequestHandler):
	""" Custom HTTP request handler.
		This class must be overridden and the following members defined:

			reports  : A dict mapping the report name to a list containing

			           1) The function that will return the list of data that
			              constitutes the report
			           2) The report's MIME type
			           3) A description of the report (will be showed on the
			              summary page)

			           An example can be:
			           reports = [generateTest, "application/pdf", "Test report"]

			virtual_report_dir  : 
			           The virtual directory which will hold the reports. A report
			           fetched by URL must be fetched with this on the path

			virtual_list_dir    :
			           GET this directory will give back an HTML file giving a
			           list of available reports
	"""

	# Page top including, CSS
	def html_top(self, title=''):
		return """
		<html>
		<head>
		  <title> %s </title>
		  <style type="text/css">
		    html,body  { border:0px; margin:0px; padding:0px; }
		    body       { background: #dedede; border:0px; margin:10px; }
		    #content   { background: #fff; border:1px; border-top: 2px; border-style: solid; border-color:black; padding:10px; padding-bottom:0px; margin-bottom:0px; }
		    #generated { background:#eee; border:1px; border-bottom-width: 2px; border-style:dotted; border-top-style: solid; border-bottom-style: solid;font-style: italic; font-size:xx-small; margin:0px; padding:0px; }
		    .header    { background:#fefefe; color:red; border-width: 1px; border-bottom-style: solid; font-size: x-large; }
		    a:link     { color:black; }
		    a:visited  { color:black; }
		    a:hover    { color:red;   }
		    a:link     { color:red;   }
		  </style>
		</head>
		<body>
		""" % title

	def html_body(self, content=''):
		return """
		<div id="content">
		  %s
		</div>
		""" % content

	def html_bottom(self):
		return """
		<div id="generated">
		<p>This page was automatically generated by the <a href="http://code.google.com/p/adt/">ADT (Agnostic Database Toolkit)</a> HTTP based report server</p>
		</div>

		</body>
		</html>
		"""

	def do_GET(self):
		# Get the files from the map set up by the subclass
		files   = self.reports.keys()

		# Virtual basedir for reports
		virtual = self.virtual_report_dir

		# Ensure the virtual path is properly "/" surrounded
		if virtual:
			if not virtual.startswith(os.sep):
				virtual  = os.sep + virtual

			if not virtual.endswith(os.sep):
				virtual += os.sep
		else:
			virtual = os.sep

		# Check if the request was for a valid report
		for fname in files:
			if self.path.endswith(virtual + fname):
				self.log_message('Opening the report "%s" for sending to the client' % fname)

				try:
					fcont = self.reports[fname][0]()
				except Exception, message:
					self.log_error('Failed to open "%s, got the error: %s"' % (fname, message))
					self.send_response(500)
					self.send_header('Content-type', 'text/html')
					self.end_headers()
					self.wfile.write(self.html_top('500 - Internal Server Error'))
					self.wfile.write(self.html_body('<span class="header">500</span><p>Internal Server Error - Failed to open the requested report file</p>'))
					self.wfile.write(self.html_bottom())
					return

				self.send_response(200)
				self.send_header('Content-type', self.reports[fname][1])
				self.end_headers()
				self.wfile.write(fcont)
				return

		# Was it a request for the list of available reports
		if self.path.replace("index.html", "").replace("/", "") == self.virtual_list_dir:
			self.log_message('Listing available reports')

			self.send_response(200)
			self.send_header('Content-type', 'text/html')
			self.end_headers()
			self.wfile.write(self.html_top())

			content = """
			<span class="header">Available reports</span>
			<p>
			The following reports are available, click on the link to get it:
			  <ul>
			"""

			for fname in self.reports.keys():
				type     = self.reports[fname][1]
				type     = type[type.find("/")+1:].upper()
				text     = self.reports[fname][2]
				content += '    <li> <a href="%s">%s (%s)</a></li>' % (virtual + fname, text, type)

			content += """
			  </ul>
			Note that it may take some time to obtain the report.
			</p>
			"""

			self.wfile.write(self.html_body(content))
			self.wfile.write(self.html_bottom())
			return
			

		self.log_message('Illegal request, returning 404. The request was for: %s' % self.path)
		self.send_response(404)
		self.send_header('Content-type', 'text/html')
		self.end_headers()
		self.wfile.write(self.html_top('404 - Report not found'))
		self.wfile.write(self.html_body('<span class="header">404</span><p>Report not found</p>'))
		self.wfile.write(self.html_bottom())
	
	def do_POST(self):
		self.send_response(403)
		self.send_header('Content-type', 'text/html')
		self.end_headers()

		self.wfile.write(self.html_top('403 - Forbidden operation'))
		self.wfile.write(self.html_body('<span class="header">403 - POST</span><p>Forbidden operation</p>'))
		self.wfile.write(self.html_bottom())

def start_server(handler_class=None, host='', port=10001):
	if not handler_class:
		raise Exception("The HTTP request handling class must be defined; invoke this function with the 'handler_class' as named parameter")

	try:
		server = HTTPServer((host, port), handler_class)
		print 'INFO  : Simple report HTTP server started...'

		server.serve_forever()
	except KeyboardInterrupt:
		print ''
		print 'INFO  : Program interrupted, report HTTP server exiting...'
		server.socket.close()		

